/*
 * Copyright 2016-present the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.github.pnoker.driver.mqtt.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import io.github.pnoker.common.entity.driver.AttributeInfo;
import io.github.pnoker.common.entity.point.PointValue;
import io.github.pnoker.common.model.Device;
import io.github.pnoker.common.model.Point;
import io.github.pnoker.common.mqtt.entity.MqttMessage;
import io.github.pnoker.common.mqtt.service.MqttReceiveService;
import io.github.pnoker.common.utils.JsonUtil;
import io.github.pnoker.driver.sdk.DriverContext;
import io.github.pnoker.driver.sdk.service.DriverSenderService;
import io.github.pnoker.driver.sdk.utils.ConvertUtil;
import io.github.pnoker.driver.sdk.utils.DriverUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author pnoker
 * @since 2022.1.0
 */
@Slf4j
@Service

//该实现类用于实现对接收的参数进行处理
public class MqttReceiveServiceImpl implements MqttReceiveService {

    @Resource
    private DriverSenderService driverSenderService;

    @Resource
    private DriverContext driverContext;


    public String getDeviceIdByName(String name) {
//        log.error(name);
//        找到所有设备
        List<Device> values = new ArrayList<>(driverContext.getDriverMetadata().getDeviceMap().values());
//        log.error(values.toString());
//        遍历设备，找到当前发内容的设备
        for (int i = 0; i < values.size(); i++) {
            Device device = values.get(i);
            if (device.getDeviceName().equals(name)) {
                log.info("get deviceID success!");
                return device.getId();
            }else {
                log.error("get deviceID fail!");
            }
        }
        return null;
    }

    public String analyticString(String value,int binaryLength){
        StringBuilder combinedBinary = new StringBuilder();
        if (!value.isEmpty()) {
            String[] singleInputValue = value.split("=");
            for (String part : singleInputValue) {
                if (!part.isEmpty()) { // 检查部分是否为空
                    int num = Integer.parseInt(part);
                    String binary = String.format("%" + binaryLength + "s", Integer.toBinaryString(num)).replace(' ', '0'); // 转换为 8 位二进制字符串
                    String reversedBinary = new StringBuilder(binary).reverse().toString(); // 倒序排列二进制字符串
                    combinedBinary.append(reversedBinary); // 将倒序排列的二进制字符串添加到合并的字符串中
                }
            }
            return combinedBinary.toString();
        }
        return null;
    }

    public void setValue(String values,String flag,String deviceId,Map<String, Map<String, AttributeInfo>> pointInfoMap){
        log.error("*** ioStatus setValue ***");
        List<PointValue> pointValues = new ArrayList<>(16);
        if (pointInfoMap != null) {
            for (String pointId : pointInfoMap.keySet()) {
                /* 获取 单个点位point 的所有数据 */
                Point point = driverContext.getPointByDeviceIdAndPointId(deviceId, pointId);
                /* 获取 单个点位point 的所有数据 */
                Map<String, AttributeInfo> infoMap = pointInfoMap.get(pointId);
                String flagValue = infoMap.get("flag").getValue();//区分inputValue/outputValue/channel/outputValue指的是机器人的E信号
//                log.error("----");
//                log.error(flagValue);
//                log.error("----");
                if (flagValue.equals(flag)){
                int targetBit = DriverUtil.value(infoMap.get("TargetBit").getType().getCode(), infoMap.get("TargetBit").getValue());
                boolean errorCode = values.charAt(targetBit - 1) == '1';//如果是1则为true，否则为false
                PointValue pointValue = new PointValue(deviceId, pointId, String.valueOf(errorCode), ConvertUtil.convertValue(point, String.valueOf(errorCode)));
                pointValue.setOriginTime(new Date());
                    if (ObjectUtil.isNotNull(pointValue)) {
                            pointValues.add(pointValue);
                    }
                }
            }
            driverSenderService.pointValueSender(pointValues);
        } else {
            log.error("*** pointInfoMap is empty !!! check your point design in website !!!  ***");
        }
//************************************************************************************************
//        PointValue pointValue = JsonUtil.parseObject(mqttMessage.getPayload(), PointValue.class);//重要
    }
    public void setValue(Map<String, Map<String, AttributeInfo>> pointInfoMap,String deviceId,JSONObject jsonObject) {
        List<PointValue> pointValues = new ArrayList<>(16);
        log.info("*** baseMsg setValue   ***");
        if (pointInfoMap != null) {
//            log.error("i am here");
            for (String pointId : pointInfoMap.keySet()) {
                /* 获取 单个点位point 的所有数据 */
                Point point = driverContext.getPointByDeviceIdAndPointId(deviceId, pointId);
                /* 获取 单个点位point 的所有数据 */
                Map<String, AttributeInfo> infoMap = pointInfoMap.get(pointId);
                String flag =  infoMap.get("flag").getValue();
//                log.error(flag);
                String baseMsg = jsonObject.getString(flag);//区分传进来的flag标识，也就是内容里面的key
//                log.error(baseMsg);
                if (flag.equals("inputValue")||flag.equals("outputValue")||flag.equals("channel")){
                    log.error("*** pointValue finished ***");
                }else{
//                    log.error("into 1");
                    if(baseMsg!=null){
//                        log.error("into 2");
                        PointValue pointValue = new PointValue(deviceId, pointId, baseMsg, ConvertUtil.convertValue(point, baseMsg));
                        pointValue.setOriginTime(new Date());
                        if (ObjectUtil.isNotNull(pointValue)) {
                            pointValues.add(pointValue);
                        }
                    }
                }
            }
            driverSenderService.pointValueSender(pointValues);
        }else {
            log.error("*** pointInfoMap is empty !!! check your point design in website !!!  ***");
        }
    }
    @Override
    public void receiveValue(MqttMessage mqttMessage) {

        // do something to process your mqtt messages
        log.info("*-*-*-*-*-*-*-*-*");
        log.info("获取到的信息如下：" + JsonUtil.toPrettyJsonString(mqttMessage));
        log.info("*-*-*-*-*-*-*-*-*");
        String mqttReceivedTopic = mqttMessage.getHeader().getMqttReceivedTopic();
        //get DeviceName by income Msg
        JSONObject jsonObject = JSONObject.parseObject(mqttMessage.getPayload());
        String deviceId = getDeviceIdByName(jsonObject.getString("name"));
        Map<String, Map<String, AttributeInfo>> pointInfoMap = driverContext.getDriverMetadata().getPointInfoMap().get(deviceId);
        String inputValues = null;
        String outputValues = null;
        String channelDiag = null;
        if (mqttMessage.getHeader().getMqttReceivedTopic().equals("dc3/default/dc3-driver-mqtt/ioStatus")) {
            log.info("*** ioStatues setting ***");
            setValue(pointInfoMap,deviceId,jsonObject);
            try {
                inputValues = analyticString(jsonObject.getString("inputValue"), 16);
                setValue(inputValues, "inputValue", deviceId, pointInfoMap);
                outputValues = analyticString(jsonObject.getString("outputValue"), 16);
                setValue(outputValues, "outputValue", deviceId, pointInfoMap);
                channelDiag = analyticString(jsonObject.getString("channel"), 8);
                setValue(channelDiag, "channel", deviceId, pointInfoMap);
            }catch (Exception e){
                log.error(JsonUtil.toJsonString(e));
            }
        }else {
            setValue(pointInfoMap,deviceId,jsonObject);
        };
//************************************************************************************************
    }
    @Override
    public void receiveValues(List<MqttMessage> mqttMessageList) {
        // do something to process your mqtt messages
        List<PointValue> pointValues = mqttMessageList.stream()
                .map(mqttMessage -> {
                    PointValue pointValue = JsonUtil.parseObject(mqttMessage.getPayload(), PointValue.class);
                    pointValue.setOriginTime(new Date());
                    return pointValue;
                }).collect(Collectors.toList());
        driverSenderService.pointValueSender(pointValues);
    }
}
